#pragma once

#include <stdio.h>
#include <pthread.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdarg.h>
#include <time.h>
#include <string.h>

// 标志输出类型
#define LOG_OUTPUT_SCREEN 1
#define LOG_OUTPUT_FILE 2

const char *glogfile = "./log.txt";

// 默认为输出到屏幕
static int _type = LOG_OUTPUT_SCREEN;

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

// 日志等级枚举
enum
{
    DEBUG = 1,
    INFO,
    WARNING,
    ERROR,
    FATAL
};


// [日志等级][pid][filename][filenumber][time]日志内容(支持可变参数)
typedef struct logmessage
{
    const char *_level;    // 日志等级
    pid_t _id;             // 进程pid
    const char *_filename; // 文件名
    int _filenumber;       // 行数
    char *_time;           // 当前时间
    char *_log_info;       // 日志内容
} logmessage;


// 函数声明
void LogMessage(const char *filename, int filenumber, int level, const char *format, ...);
logmessage *creat_lg();
void destroy();
const char *LevelToString(int level);
char *GetTime();
void Flushlog(logmessage *lg);
void FlushLogToSreen(logmessage *lg);
void FlushLogToFile(logmessage *lg);
void Enable(int type);

// 设置日志输出类型
void Enable(int type)
{
    _type = type;
}

// 创建日志消息结构体
logmessage *creat_lg()
{
    logmessage *lg = (logmessage *)malloc(sizeof(logmessage));
    return lg;
}

// 释放内存
void destroy(logmessage *lg)
{
    if (lg == NULL)
        return;
    free(lg->_time);
    free(lg->_log_info);
    free(lg);
}

// 刷新日志消息
void Flushlog(logmessage *lg)
{
    pthread_mutex_lock(&mutex);
    if (_type == LOG_OUTPUT_SCREEN)
    {
        FlushLogToSreen(lg);
    }
    else if (_type == LOG_OUTPUT_FILE)
    {
        FlushLogToFile(lg);
    }
    pthread_mutex_unlock(&mutex);
}

// 将日志消息输出到屏幕
void FlushLogToSreen(logmessage *lg)
{
    printf("[%s][%d][%s][%d][%s] %s",
           lg->_level,
           lg->_id,
           lg->_filename,
           lg->_filenumber,
           lg->_time,
           lg->_log_info);
}

// 将日志消息输出到文件
void FlushLogToFile(logmessage *lg)
{
    FILE *f = fopen(glogfile, "a");
    char logtxt[2048];
    snprintf(logtxt, sizeof(logtxt), "[%s][%d][%s][%d][%s] %s",
             lg->_level,
             lg->_id,
             lg->_filename,
             lg->_filenumber,
             lg->_time,
             lg->_log_info);
    fprintf(f, "%s", logtxt);
    fclose(f);
}

// 将日志级别转换为字符串
const char *LevelToString(int level)
{
    switch (level)
    {
    case DEBUG:
        return "DEBUG";
    case INFO:
        return "INFO";
    case WARNING:
        return "WARNING";
    case ERROR:
        return "ERROR";
    case FATAL:
        return "FATAL";
    default:
        return "UNKNOW";
    }
}

// 获取当前时间字符串
char *GetTime()
{
    time_t now = time(NULL);
    struct tm *curr_time = localtime(&now);
    char *buffer = (char *)malloc(128);
    snprintf(buffer, 128, "%d-%02d-%02d %02d:%02d:%02d",
             curr_time->tm_year + 1900,
             curr_time->tm_mon + 1,
             curr_time->tm_mday,
             curr_time->tm_hour,
             curr_time->tm_min,
             curr_time->tm_sec);
    return buffer;
}

// 记录日志消息
void LogMessage(const char *filename, int filenumber, int level, const char *format, ...)
{

    logmessage *lg = creat_lg();

    lg->_filename = filename;
    lg->_filenumber = filenumber;
    lg->_id = getpid();
    lg->_level = LevelToString(level);
    lg->_time = GetTime();

    lg->_log_info = (char *)malloc(1024);
    // 获取可变参数
    va_list ap;
    va_start(ap, format);
    vsnprintf(lg->_log_info, 1024, format, ap);
    va_end(ap);

    // 打印日志
    Flushlog(lg);

    // 释放内存
    destroy(lg);
}

#define LOG(Level, Format, ...)do{LogMessage(__FILE__, __LINE__, Level, Format, ##__VA_ARGS__);} while (0)
// 打印到显示器
#define EnableScreen()do{Enable(LOG_OUTPUT_SCREEN); } while (0)
// 打印到文件
#define EnableFILE()do{Enable(LOG_OUTPUT_FILE); } while (0)

//过滤DEBUG信息
